package com.cheng.snake;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import java.util.Timer;
import static javax.swing.WindowConstants.EXIT_ON_CLOSE;

public class SnakeApplication
        extends JPanel
{
    //储存蛇单元的集合
    public static List<Rectangle> rectangles;

    //粮食正方形
    public static Rectangle foodRectangle;

    //记忆正方形，永远记得蛇尾走之前的位置，蛇变长了就加到这
    public static Rectangle memoryRectangle;

    //蛇的状态码
    public static final int UP = 1;
    public static final int DOWN = 3;
    public static final int LEFT = 2;
    public static final int RIGHT = 4;

    //按键的状态
    public static boolean isLeftDown;
    public static boolean isRightDown;
    public static boolean isUpDown;
    public static boolean isDownDown;
    public static boolean isSpaceDown;

    //游戏状态
    public static final int END = 0;
    public static final int GAMING = 1;
    public static final int READY = 2;

    //速度
    public static int speed = 1;

    //定时器
    public static Timer timer = new Timer();

    //蛇的方向，初始时刻蛇往右走
    public static int direction = SnakeApplication.RIGHT;

    //全局随机数器
    public static Random random;

    //游戏状态
    public static int state = READY;
    public static boolean stateChange = false;
    public static SnakeApplication snakeApplication;

    static
    {
        rectangles = new ArrayList<>();
    }

    public static void initialize(JFrame jFrame)
            throws InterruptedException
    {
        System.out.println("游戏初始化");
        Thread.sleep(500);
        state = READY;
        stateChange = true;
        speed = 1;
        timer.cancel();
        timer = new Timer();
        direction = RIGHT;
        random = new Random(System.currentTimeMillis());


        rectangles = new ArrayList<>();
        foodRectangle = new Rectangle();
        memoryRectangle = new Rectangle();

        System.out.println("游戏初始化完成");

    }

    public static void main(String[] args)
            throws InterruptedException
    {
        JFrame jFrame = new JFrame();
        jFrame.setVisible(true);//显示窗口
        jFrame.setBounds(0, 0, 518, 540);//设置大小
        jFrame.setDefaultCloseOperation(EXIT_ON_CLOSE);//设置窗口关闭方式为点叉关闭
        jFrame.setResizable(false);//设置窗口为不可改变大小
        snakeApplication = new SnakeApplication();
        jFrame.add(snakeApplication);


        jFrame.addMouseListener(new MouseAdapter()
        {
            @Override
            public void mouseClicked(MouseEvent e)
            {
                System.out.println(state);
                if (state == READY)
                {
                    try
                    {
                        initialize(jFrame);
                    }
                    catch (InterruptedException ex)
                    {
                        ex.printStackTrace();
                    }
                    startGame(jFrame);
                }
                else if (state == END)
                {
                    state = READY;
                    snakeApplication.repaint();
                }

            }
        });

    }

    public static void startGame(JFrame jFrame)
    {
        state = GAMING;
        stateChange = true;
        //默认短蛇
        rectangles.add(new Rectangle(10, 10));
        rectangles.add(new Rectangle(9, 10));
        rectangles.add(new Rectangle(8, 10));
        rectangles.add(new Rectangle(7, 10));

        memoryRectangle = new Rectangle(6, 10);
        foodRectangle = new Rectangle(random.nextInt(25) + 1
                , random.nextInt(25) + 1);

        snakeApplication.move();//蛇走

        jFrame.addKeyListener(new KeyListener()
        {

            @Override
            public void keyTyped(KeyEvent e)
            {

            }

            @Override
            public void keyPressed(KeyEvent e)
            {
                //按键按下后设置对应按键状态并且立即执行动作，同时如果已经按下了就不管了，
                if (e.getKeyCode() == KeyEvent.VK_LEFT && direction != RIGHT && direction != LEFT && !isLeftDown)
                {
                    isLeftDown = true;
                    direction = LEFT;
                    snakeApplication.move();
                }
                if (e.getKeyCode() == KeyEvent.VK_RIGHT && direction != LEFT && direction != RIGHT && !isRightDown)
                {
                    isRightDown = true;
                    direction = RIGHT;
                    snakeApplication.move();
                }
                if (e.getKeyCode() == KeyEvent.VK_UP && direction != DOWN && direction != UP && !isUpDown)
                {
                    isUpDown = true;
                    direction = UP;
                    snakeApplication.move();
                }
                if (e.getKeyCode() == KeyEvent.VK_DOWN && direction != UP && direction != DOWN && !isDownDown)
                {
                    isDownDown = true;
                    direction = DOWN;
                    snakeApplication.move();
                }
                if (e.getKeyCode() == KeyEvent.VK_SPACE && !isSpaceDown)
                {
                    isSpaceDown = true;
                    snakeApplication.move();
                }
                snakeApplication.repaint();
            }

            @Override
            public void keyReleased(KeyEvent e)
            {
                isLeftDown = (e.getKeyCode() == KeyEvent.VK_LEFT) ? false : isLeftDown;
                isRightDown = (e.getKeyCode() == KeyEvent.VK_RIGHT) ? false : isRightDown;
                isUpDown = (e.getKeyCode() == KeyEvent.VK_UP) ? false : isUpDown;
                isDownDown = (e.getKeyCode() == KeyEvent.VK_DOWN) ? false : isDownDown;
                if (e.getKeyCode() == KeyEvent.VK_SPACE)
                {
                    isSpaceDown = false;
                    snakeApplication.move();
                }

            }
        });
        snakeApplication.repaint();
    }

    public static void eat()
    {
        //设置粮食位置为记忆位置并且把粮食变成蛇的一部分
        foodRectangle.setX(memoryRectangle.getX());
        foodRectangle.setY(memoryRectangle.getY());
        rectangles.add(foodRectangle);
        //生成粮食新位置，并且判断是否生成在蛇身上，如果是则重新生成直到不在
        foodRectangle = new Rectangle();
        boolean isCoincidence = true;
        while (isCoincidence)
        {
            isCoincidence = false;
            foodRectangle.setX(random.nextInt(0, 25) + 1);
            foodRectangle.setY(random.nextInt(0, 25) + 1);
            for (Rectangle rectangle : rectangles)
            {
                isCoincidence = (foodRectangle.getX() == rectangle.getX()) && (foodRectangle.getY() == rectangle.getY()) ? true : isCoincidence;
            }
            System.out.println();
        }
    }

    //判断蛇头位置是否与粮食重合
    public static boolean isEat()
    {
        if (rectangles.get(0).getX() == foodRectangle.getX() && rectangles.get(0).getY() == foodRectangle.getY())
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public static boolean isDie()
    {
        Rectangle head = rectangles.get(0);
        if (head.getX() > 25 || head.getX() < 1 || head.getY() > 25 || head.getY() < 1)
        {
            return true;
        }
        for (Rectangle rectangle : rectangles)
        {
            if (head != rectangle && head.getX() == rectangle.getX() && head.getY() == rectangle.getY())
            {
                return true;
            }
        }
        return false;
    }

    //蛇走
    //先看空格，如果按下了就设置速度快
    //清空定时器重新根据速度设置一个定时器
    public void move()
    {
        speed = isSpaceDown ? 5 : 2;
        timer.cancel();
        timer = new Timer();
        timer.schedule(new TimerTask()
        {

            @Override
            public void run()
            {
                synchronized (rectangles)
                {
                    if (direction == UP)
                    {
                        moveUp();
                    }
                    else if (direction == DOWN)
                    {
                        moveDown();
                    }
                    else if (direction == LEFT)
                    {
                        moveLeft();
                    }
                    else if (direction == RIGHT)
                    {
                        moveRight();
                    }
                    if (isEat())
                    {
                        eat();
                    }
                    if (isDie())
                    {
                        state = END;
                        timer.cancel();
                    }
                }
                repaint();

            }
        }, 0, 500 / speed);
    }

    //蛇向上下左右走
    public void moveUp()
    {
        Rectangle rectangle = rectangles.remove(rectangles.size() - 1);

        //设置记忆块位置
        memoryRectangle.setX(rectangle.getX());
        memoryRectangle.setY(rectangle.getY());

        //移动蛇尾到头
        rectangle.setY(rectangles.get(0).getY() - 1);
        rectangle.setX(rectangles.get(0).getX());
        rectangles.add(0, rectangle);
    }

    public void moveDown()
    {
        Rectangle rectangle = rectangles.remove(rectangles.size() - 1);

        memoryRectangle.setX(rectangle.getX());
        memoryRectangle.setY(rectangle.getY());

        rectangle.setY(rectangles.get(0).getY() + 1);
        rectangle.setX(rectangles.get(0).getX());
        rectangles.add(0, rectangle);
    }

    public void moveLeft()
    {
        Rectangle rectangle = rectangles.remove(rectangles.size() - 1);

        memoryRectangle.setX(rectangle.getX());
        memoryRectangle.setY(rectangle.getY());

        rectangle.setY(rectangles.get(0).getY());
        rectangle.setX(rectangles.get(0).getX() - 1);
        rectangles.add(0, rectangle);
    }

    public void moveRight()
    {
        Rectangle rectangle = rectangles.remove(rectangles.size() - 1);

        memoryRectangle.setX(rectangle.getX());
        memoryRectangle.setY(rectangle.getY());

        rectangle.setY(rectangles.get(0).getY());
        rectangle.setX(rectangles.get(0).getX() + 1);
        rectangles.add(0, rectangle);
    }

    @Override
    public void paint(Graphics g)
    {
        super.paint(g);
        if (state == READY)
        {
            g.drawString("开始游戏", 200, 200);
            return;
        }
        else if (state == END)
        {
            g.drawString("游戏结束\n重新开始", 200, 200);
            return;
        }
        Graphics2D graphics2D = (Graphics2D) g;

        if (rectangles.size() == 0)
        {
            return;
        }

        //循环绘制集合里的方块
        synchronized (rectangles)
        {
            graphics2D.drawRect(1, 1, 500, 500);
            for (Rectangle rectangle : rectangles)
            {
                if (rectangles.indexOf(rectangle) - 1 != -1)
                {
                    Rectangle rectangleLast = rectangles.get(rectangles.indexOf(rectangle) - 1);
                    paintRectangle(rectangleLast.getAbsX() + 7,
                            rectangleLast.getAbsY() + 7,
                            rectangle.getAbsX() + 13,
                            rectangle.getAbsY() + 13,
                            graphics2D);
                }
                graphics2D.fillRect(rectangle.getAbsX() + 1, rectangle.getAbsY() + 1, 18, 18);

            }
        }
        graphics2D.fillRect(foodRectangle.getAbsX() + 1, foodRectangle.getAbsY() + 1, 18, 18);
    }

    //给出对角坐标画正方形的方法
    public void paintRectangle(int startX, int startY, int endX, int endY, Graphics2D g)
    {
        Color color = g.getColor();
//        g.setColor(Color.blue);
        g.fillRect(startX < endX ? startX : endX, startY < endY ? startY : endY
                , Math.abs(endX - startX), Math.abs(endY - startY));
        g.setColor(color);
    }
}
